package com.itextpdf.local.ess.PDFLocation;

import com.itextpdf.awt.geom.Rectangle2D;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.SimpleBookmark;
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
import com.itextpdf.text.pdf.parser.RenderListener;
import com.itextpdf.text.pdf.parser.TextRenderInfo;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class LocationFactory {
    /**
     * 坐标定位
     * @param X X
     * @param Y Y
     * @param pageNum pageNum
     * @return 坐标位置
     */
    public PDELocation getLocationXY(float X,float Y,int pageNum){
        return new XYLocation(X,Y,pageNum);
    }

    /**
     * 关键字定位
     * @param file 文件
     * @param keyWord 关键字
     * @param num 关键字序号
     * @return 坐标位置
     */
    public PDELocation getLocationKeyword(byte[] file,String keyWord,int num){
        PdfReader reader = null;
        List<PDELocation> fiList = new ArrayList<>();
        char[] a = keyWord.replace(" ","").toLowerCase().toCharArray();
        try {
            reader = new PdfReader(file);
            //获得pdf的页码
            int pageNum = reader.getNumberOfPages();
            List<PDELocation> locations = null;
            //循环每一页 获得所有的关键字
            for (int i = 0; i< pageNum; i++) {
                try {
                    locations = getKeyWords(reader, i+1);
                } catch (IOException e) {
                    continue;
                }
                if (locations.size() > 0) {
                    //根据解析函数筛选包含的关键字（因为pdf中的文本是不规则长度和断句的需要进行筛选）
                    List<PDELocation> list2 = check(locations, a);
                    //把筛选到的内容放入集合中
                    fiList.addAll(list2);

                }else if (i > 0) {
                    //不是第一页的时候继续循环
                    continue;
                }else {
                    //到达第1页结束后关闭reader
                    reader.close();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (reader != null) {
                reader.close();
            }
        }
        if (num == 0){
            return fiList.get(fiList.size()-1);
        }
        if (fiList.size()>=num){
            return fiList.get(num-1);
        }else {
            return fiList.get(fiList.size()-1);
        }
    }

    /**
     * 关键字定位 关键字定位
     * @param file 文件
     * @param keyWord 关键字
     * @param num 关键字序号
     * @return 坐标位置
     */
    public PDELocation getLocationKeyword(byte[] file,String keyWord,int num,int pageNum){
        PdfReader reader = null;
        List<PDELocation> fiList = new ArrayList<>();
        char[] a = keyWord.replace(" ","").toLowerCase().toCharArray();
        try {
            reader = new PdfReader(file);
            int pageNum1 = reader.getNumberOfPages();
            if (pageNum1<pageNum){
                pageNum = pageNum1;
            }
            List<PDELocation> locations = getKeyWords(reader, pageNum);
            if (locations.size() > 0) {
                //根据解析函数筛选包含的关键字（因为pdf中的文本是不规则长度和断句的需要进行筛选）
                List<PDELocation> list2 = check(locations, a);
                //把筛选到的内容放入集合中
                fiList.addAll(list2);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (reader != null) {
                reader.close();
            }
        }
        if (num == 0){
            return fiList.get(fiList.size()-1);
        }
        if (fiList.size()>=num){
            return fiList.get(num-1);
        }else {
            return fiList.get(fiList.size()-1);
        }
    }

    /**
     * 书签定位
     * @param file 文件
     * @param BookMark 书签
     * @return 坐标位置
     */
    public PDELocation getLocationBookMark(byte[] file,String BookMark){
        PdfReader reader = null;
        PDELocation location = null;
        try {
            reader = new PdfReader(file);
            List<HashMap<String, Object>> bmList = SimpleBookmark.getBookmark(reader);
            if (bmList != null) {
                for(HashMap<String, Object> hm :bmList){
                    if(BookMark.equals(hm.get("Title"))) {
                        String[] a = hm.get("Page").toString().split(" ");
                        location = new XYLocation(BookMark,Float.parseFloat(a[2]),Float.parseFloat(a[3]),0,0,Integer.parseInt(a[0]));
                    }
                }
            }
        }catch (Exception exception){
            exception.printStackTrace();
        }
        finally {
            if (reader != null) {
                reader.close();
            }
        }
        return location;
    }

    /**
     *  解析关键字的方法 根据输入的页面所有的内容的集合和关键字的char 数组进行匹配
     * @param list
     * @param chars
     * @return
     */
    private List<PDELocation> check(List<PDELocation> list, char[] chars) {
        //定义一个容器集合 收集位置信息对象
        List<PDELocation> list2 = new ArrayList<>();
        //获得关键字的长度
        int length = chars.length;
        //循环某个页面中的所有内容
        for (int i = 0; i < list.size(); i++) {
            //关键字出现在某个词组的位置
            int lo = -1;
            //如果大于-1 则代表出现了关键字的第一个字
            if ((lo = list.get(i).getContent().indexOf(chars[0])) > -1) {
                //进一步判断，获得该对象的所有文字内容
                String s = list.get(i).getContent();
                //计数变量
                int count=0;
                //把该词条后的n个词条加起来 并且n要小于关键字的长度且n加上当前的次数要小于总集合的长度
                for (int j = 1; j < length && (j + i) < list.size(); j++) {
                    s += list.get(i + j).getContent();
                    //更新计数次数，以便后面循环跳过计数次数个对象
                    count=j;
                }
                //如果组合的文字包含关键字内容，并且是从当前第一个文字对象起始的
                if (s.contains(new String(chars)) && s.indexOf(new String(chars))<list.get(i).getContent().length()) {
                    //更新位置信息，放入集合中
                    PDELocation location1 = list.get(i);

                    int textlength = location1.getContent().length();
                    float x = location1.getX() +(float) location1.getWidth() * ((float) lo / textlength);
                    float y =location1.getY();
                    int page = location1.getPageNum();
                    XYLocation location = new XYLocation(new String(chars),x,y,0,0,page);
                    list2.add(location);
                    //向后推移count个对象
                    i=i+count;
                }  //循环继续
            }
        }
        //返回筛选过的集合
        return list2;
    }

    //获得某一页的关键字信息的集合
    private List<PDELocation> getKeyWords(PdfReader pdfReader, final int pageNum) throws IOException {
        List<PDELocation> locations = new ArrayList<>();
        PdfReaderContentParser pdfReaderContentParser = new PdfReaderContentParser(pdfReader);
        pdfReaderContentParser.processContent(pageNum, new RenderListener() {
            @Override
            public void beginTextBlock() {
            }
            @Override
            public void renderText(TextRenderInfo textRenderInfo) {
                //去除pdf中文本的空格
                String strings=textRenderInfo.getText().replace(" ", "").toLowerCase();
                //当文本长度大于0的时候获得文字矩形范围
                if (strings.length() > 0) {
                    Rectangle2D.Float baseFloat = textRenderInfo.getBaseline()
                            .getBoundingRectange();
                    Rectangle2D.Float ascentFloat = textRenderInfo.getAscentLine()
                            .getBoundingRectange();
                    //左上角坐标
                    float x = baseFloat.x;
                    float y = baseFloat.y + ((ascentFloat.y - baseFloat.y) );
                    double width = baseFloat.getWidth();
                    double height = baseFloat.getHeight();
                    //把文字的相关信息封装成location对象加入集合，此处为某个页面的所有文字信息
                    locations.add(new XYLocation(strings, x, y, width, height, pageNum));
                }
            }
            @Override
            public void endTextBlock() {
            }
            @Override
            public void renderImage(ImageRenderInfo imageRenderInfo) {
            }
        });
        return locations;
    }

}
